#include "lib/decoders/wav/pvmvoicesourcewav.h"
#include "lib/decoders/wav/pvmdatasourcewav.h"
#include "lib/decoders/wav/pvmvoicewav.h"
#include "lib/decoders/wav/pvmvoiceimaadpcmwav.h"

#include "lib/memory/pvmmemory.h"

PVMVoiceSourceWAV::PVMVoiceSourceWAV()
{
	dataSource = NULL;

	PVMInitCritical(&critical);
}

PVMVoiceSourceWAV::~PVMVoiceSourceWAV()
{
	if(dataSource)
		dataSource->Release();

	dataSource = NULL;
	PVMDeinitCritical(&critical);
}

IPVMVoice* PVMVoiceSourceWAV::CreateVoice(pvm_int samplesPerSecond, pvm_int bitsPerSample, pvm_int chanelsNum)
{
	IPVMVoice *newVoice = NULL;
	PVMDataSourceWAV* crateDataSource = dataSource;

	PVMEnterCritical(&critical);
	if(crateDataSource->GetRefCount()>1)
	{
		crateDataSource = dataSource->CreateCopy();
		if(crateDataSource==NULL)
		{
			PVMLeaveCritical(&critical);
			return NULL;
		}
	}
	else
	{
		if(crateDataSource->stream->Tell()!=crateDataSource->dataOffset)
		{
			crateDataSource->SeekAtStart();
		}
	}

	switch(crateDataSource->formatHeader.audioFormat)
	{
	case 1:
		newVoice = PVMVoiceWAV::Create(crateDataSource, samplesPerSecond, bitsPerSample, chanelsNum);
		break;
	case 0x11:
		newVoice = PVMVoiceIMAAPDPCMWAV::Create(crateDataSource, samplesPerSecond, bitsPerSample, chanelsNum);
		break;
	}

	PVMLeaveCritical(&critical);
	return newVoice;
}

void PVMVoiceSourceWAV::Destroy()
{
	delete( this);
}

pvm_int PVMVoiceSourceWAV::GetLengthMS()
{
	if(!dataSource||dataSource->stream==NULL)
		return -1;

	return (pvm_int)(((pvm_int64)dataSource->dataSize/dataSource->formatHeader.blockAlign)*1000/dataSource->formatHeader.sampleRate);
}

PVMVoiceSourceWAV* PVMVoiceSourceWAV::Create(IPvmInStream* inStream, pvm_int8* initialData, pvm_uint initialSize, 
									pvm_uint dataOffset, pvm_uint dataSize, FmtHeader& formatHeader)
{
	PVMDataSourceWAV* crateDataSource = PVMDataSourceWAV::Create(inStream, false, initialData, initialSize, dataOffset, dataSize, formatHeader);

	if(!crateDataSource)
		return NULL;

	crateDataSource->AddRef();

	PVMVoiceSourceWAV* newSrc = new PVMVoiceSourceWAV();

	if(!newSrc)
	{
		crateDataSource->Release();
		return NULL;
	}

	newSrc->dataSource = crateDataSource;
	return newSrc;
}

pvm_bool PVMVoiceSourceWAV::GetOption(const pvm_char* /*optionName*/, void* /*optionVal*/, pvm_uint32* /*optionSize*/)
{
	return false;
}

pvm_bool PVMVoiceSourceWAV::SetOption(const pvm_char* /*optionName*/, void* /*optionVal*/, pvm_uint32 /*optionSize*/)
{
	return false;
}
